package models

import (
	"fmt"
	"gitchina/kly_service/data"
	"gitchina/kly_service/errors"
	"gitchina/kly_service/template"
	"gitchina/kly_service/util"
	"regexp"
)

const (
	default_inviter = "011010000000zr7"
	phone_pattern   = "^1[3|4|5|7|8][0-9]\\d{8}$"
)

type Member struct{}

type AddMemberRQ struct {
	Phone        string `json:"phone"`
	VerifyCode   string `json:"verify_code"`
	Passwd       string `json:"password"`
	RegisterId   string `json:"register_id"`
	Platform     string `json:"platform"`
	Inviter      ID     `json:"inviter"`
	MemberType   int    `json:"-"`
	ImageRootDir string `json:"-"`
	ImageCdn     string `json:"-"`
}

type UpdPasswdRQ struct {
	Phone  string `json:"phone"`
	Code   string `json:"verify_code"`
	Passwd string `json:"password"`
}

type SendRegistryVerifyCodeRQ struct {
	Phone string `json:"phone"`
}

type GetMemberInfoRQ struct {
	MemberId ID `json:"member_id"`
}

type MemberRS struct {
	Id           ID     `json:"member_id"`
	RawId        int    `json:"-"`
	Token        string `json:"token"`
	Name         string `json:"name"`
	NickName     string `json:"nick_name"`
	Phone        string `json:"phone"`
	MemberType   int    `json:"member_type"`
	Level        int    `json:"level"`
	AuthLevel    int    `json:"auth_level"`
	PhotoUrl     string `json:"photo_url"`
	QRCodeUrl    string `json:"qrcode_url"`
	IDCardFS     string `json:"-"`
	IDCardRS     string `json:"-"`
	IDCardNo     string `json:"-"`
	QRCodeExists bool   `json:"-"`
	State        int    `json:"-"`
}

type MemberBriefInfoRS struct {
	Id       ID     `json:"member_id"`
	Name     string `json:"name"`
	NickName string `json:"nick_name"`
	PhotoUrl string `json:"photo_url"`
}

func (m Member) AddMember(rq *AddMemberRQ) (mbrId ID, err error) {
	var inviterId int64
	var exists bool
	var repo data.MemberRepo
	if rq.Inviter == "" {
		rq.Inviter = ID(default_inviter)
	}
	if exists, err = repo.Exists(rq.Phone); !exists && err == nil {
		if err = addMemberCheck(rq); err == nil {
			_, _, _, inviterId, err = rq.Inviter.Decode()
			if err != nil {
				util.GetLogger().Error("[model] - add member error. unexpected mbrId:%s", string(rq.Inviter))
				err = errors.New(errors.MSG_Mbr_Invalid_Inviter)
			} else {
				id, err := repo.AddMember(&data.MemberDto{
					Phone:   rq.Phone,
					Passwd:  rq.Passwd,
					Inviter: int(inviterId),
					TypeId:  rq.MemberType,
				})
				if err != nil {
					util.GetLogger().Error("[model] - add member error: %s", err.Error())
					err = errors.New(errors.MSG_Mbr_Add_Error)
				} else {
					mbrId.Encode(ID_Shard, ID_Ver, ID_Member_Category, id)
					m.AddQRCode(rq.ImageCdn, string(mbrId), rq.ImageRootDir, int(id))
				}
			}
		}
	} else {
		if err != nil {
			util.GetLogger().Error("[model] - add member error: %s", err.Error())
			err = errors.New(errors.MSG_Mbr_Add_Error)
		} else {
			err = errors.New(errors.MSG_Mbr_Exists)
		}
	}

	return
}

func (m Member) AddQRCode(cdn, mbrId, dir string, id int) {
	var repo data.MemberRepo
	err := util.GenQRCode(fmt.Sprintf("%sqrcode/%s.png", dir, mbrId), mbrId)
	if err == nil {
		_, err := repo.AddQRCode(id, fmt.Sprintf("%sqrcode/%s.png", cdn, mbrId))
		if err != nil {
			util.GetLogger().Error("[model] - add qrcode error: %s", err.Error())
		}
	} else {
		util.GetLogger().Error("[model] - add qrcode error: %s", err.Error())
	}

}

func (m Member) GetMemberInfo(mbrId ID) (rs MemberRS, err error) {
	var id int64
	var repo data.MemberRepo
	_, _, _, id, err = mbrId.Decode()
	if err != nil {
		util.GetLogger().Error("[model] - get member. unexpected mbrId:%s", string(mbrId))
		err = errors.New(errors.MSG_Mbr_Invalid)
	} else {
		mbr, err := repo.GetMemberInfo(int(id))
		if err == nil {
			rs = MemberRS{
				Id:         mbrId,
				Name:       mbr.Name,
				NickName:   mbr.NickName,
				Phone:      mbr.Phone,
				MemberType: mbr.TypeId,
				Level:      mbr.Level,
				AuthLevel:  mbr.AuthLevel,
				PhotoUrl:   mbr.PhotoUrl,
				QRCodeUrl:  mbr.QRCode,
				IDCardFS:   mbr.IDCardFS,
				IDCardRS:   mbr.IDCardRS,
			}
		} else {
			util.GetLogger().Error("[model] - get member info error: %s", err.Error())
			err = errors.New(errors.MSG_Mbr_Get_Error)
		}
	}
	return
}

func (m Member) UpdatePasswd(phone, code, passwd string) (err error) {
	var ok bool
	var repo data.MemberRepo
	if ok, err = repo.VerifyCode(phone, code); ok && err == nil {
		ok, err = repo.UpdatePasswd(phone, passwd)
		if !ok || err != nil {
			util.GetLogger().Error("[model] - update password error: %s", err.Error())
			err = errors.New(errors.MSG_Mbr_Upd_Passwd_Error)
		}
	} else {
		util.GetLogger().Error("[model] - update password error: %s", err.Error())
		err = errors.New(errors.MSG_Mbr_Invalid_VerifyCode)
	}
	return
}

func (m Member) SendRegistryVerifyCode(phone string) (err error) {
	var ok bool
	var repo data.MemberRepo
	var code = util.GenVerifyCode(6)
	if ok, err = repo.AddCode(phone, code); ok {
		util.SendSms(phone, template.GetRegistryVerifyCodeTemplate(code))
	} else {
		if err != nil {
			util.GetLogger().Error("[model] - send sms error: %s", err.Error())
		}
		err = errors.New(errors.MSG_Mbr_Send_SMS_Failed)
	}

	return err
}

func addMemberCheck(rq *AddMemberRQ) (err error) {
	var match bool
	if match, err = regexp.MatchString(phone_pattern, rq.Phone); !match {
		util.GetLogger().Error("[model] - unexpected phone: %s", rq.Phone)
		err = errors.New(errors.MSG_Mbr_Invalid_Phone)
		return
	}
	if len(rq.Passwd) < 6 {
		err = errors.New(errors.MSG_Mbr_Passwd_Too_Short)
		return
	}
	if !verifyCode(rq.Phone, rq.VerifyCode) {
		err = errors.New(errors.MSG_Mbr_Invalid_VerifyCode)
		return
	}
	return
}

func checkMemberType(mbrType int) error {
	var err error
	//1. carrier owner
	//2. cargo owner
	//3. corp
	if mbrType < 1 || mbrType > 3 {
		err = errors.New(errors.MSG_Mbr_Invalid_MemberType)
	}
	return err
}

func verifyCode(phone, code string) bool {
	var r data.MemberRepo
	valid, _ := r.VerifyCode(phone, code)
	return valid
}
